///////////////////////////////////////////////////////////////////////////////
// Name:        opencv.cpp
// Purpose:     OpenCV API wrappers
// Copyright:   (c) 2006, Ivan Laptev, TT Solutions
// License:     GPL, Please contact us for commercial license.
//              http://www.tt-solutions.com/
///////////////////////////////////////////////////////////////////////////////
#include "objectdet/common.h"

namespace
{
    struct DestroyFileStorage
    {
        void operator() (CvFileStorage * ptr)
        {
            cvReleaseFileStorage(&ptr);
        }
    };
    struct DestroyMat
    {
        void operator() (CvMat * ptr)
        {
            cvReleaseMat(&ptr);
        }
    };
    struct DestroyMatHeader
    {
        void operator() (CvMat * ptr)
        {
            cvReleaseMatHeader(&ptr);
        }
    };
    struct DestroyImage
    {
        void operator() (IplImage* ptr)
        {
            cvReleaseImage(&ptr);
        }
    };
}

pFileStorage guard(CvFileStorage* ptr)
{
    return pFileStorage(ptr, DestroyFileStorage());
}

pMat guard(CvMat* ptr)
{
    return pMat(ptr, DestroyMat());
}

pMat guardHeader(CvMat* ptr)
{
    return pMat(ptr, DestroyMatHeader());
}

pImage guard(IplImage* ptr)
{
    return pImage(ptr, DestroyImage());
}

pMat CreateMat(unsigned int rows, unsigned int cols, int type)
{
    return guard(cvCreateMat(rows, cols, type));
}

pMat CreateMatHeader(unsigned int rows, unsigned int cols, int type)
{
    return guardHeader(cvCreateMatHeader(rows, cols, type));
}

void SetData(pMat const& arr, void* data, int step)
{
    cvSetData(arr.get(), data, step);
}

pMat CloneMat(pMat const& matrix)
{
    return guard((CvMat*)cvCloneMat(matrix.get()));
}

pFileStorage OpenFileStorage(std::string const& filename, ReadWriteMode mode)
{
    return guard(cvOpenFileStorage(filename.c_str(), NULL,
                                   mode == RWM_Read ? CV_STORAGE_READ : CV_STORAGE_WRITE));
}

void WriteMatrixToFile(pFileStorage fs, std::string const& name, pMat const& mat)
{
    cvWrite(fs.get(), name.c_str(), mat.get(), cvAttrList(0,0));
}

pMat ReadMatrixFromFile(pFileStorage fs, std::string const& name)
{
    CvFileNode* node = cvGetFileNodeByName(fs.get(), 0, name.c_str());
    // TODO ASSERT(node != NULL)
    if (!node)
        return pMat(); // NULL
    return dummyGuard<CvMat>((CvMat*)cvRead(fs.get(), node, NULL));
}

void ConvertScale(pMat const& a, pMat b, double scale, double shift)
{
    cvScale(a.get(), b.get(), scale, shift);
}

void Sobel(pMat const& src, pMat dst, int xorder, int yorder, int aperture_size)
{
    cvSobel(src.get(), dst.get(), xorder, yorder, aperture_size);
}

void Smooth(pMat const& src, pMat dst, SmoothMode mode,
            int param1, int param2, double param3)
{
    cvSmooth(src.get(), dst.get(), mode, param1, param2, param3);
}

void* DoPtr2D(pMat const& mat, int idx0, int idx1)
{
    return cvPtr2D(mat.get(), idx0, idx1);
}

double GetReal2D(pMat const& mat, int idx0, int idx1)
{
    return cvGetReal2D(mat.get(), idx0, idx1);
}

void SetReal2D(pMat mat, int idx0, int idx1, double value)
{
    cvSetReal2D(mat.get(), idx0, idx1, value);
}

void CopyMatrix(pMat const& src, pMat dst, pMat mask)
{
    return cvCopy(src.get(), dst.get(), mask.get());
}

void CvtColor(pMat const& src, pMat const& dst, int code)
{
    return cvCvtColor(src.get(), dst.get(), code);
}

void Multiply(pMat const& src1, pMat const& src2, pMat dst, double scale)
{
    cvMul(src1.get(), src2.get(), dst.get(), scale);
}

void MatrixMultiply(pMat const& src1, pMat const& src2, pMat dst)
{
    cvMatMul(src1.get(), src2.get(), dst.get());
}

void Divide(pMat const& src1, pMat const& src2, pMat dst, double scale)
{
    cvDiv(src1.get(), src2.get(), dst.get(), scale);
}

void GEMM(pMat const& src1, pMat const& src2, double alpha,
          pMat const& src3, double beta,
          pMat dst, int tABC)
{
    cvGEMM(src1.get(), src2.get(), alpha, src3.get(), beta, dst.get(), tABC);
}

void Resize(pMat const& src, pMat dst, ResizeMode interpolation)
{
    return cvResize(src.get(), dst.get(), interpolation);
}

void SetValue(pMat const& arr, CvScalar const& value, pMat const mask)
{
    cvSet(arr.get(), value, mask.get());
}

void PowerMatrix(pMat const& src, pMat dst, double power)
{
    cvPow(src.get(), dst.get(), power);
}

void Merge(pMat const& src0, pMat const& src1, pMat const& src2, pMat const& src3,
           pMat dst)
{
    cvMerge(src0.get(), src1.get(), src2.get(), src3.get(), dst.get());
}

void FlipMatrix(pMat const& src, pMat dst, int flip_mode)
{
    cvFlip(src.get(), dst.get(), flip_mode);
}
